﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Engine.Dtd.Schema;
using System.Xml;
using System.IO;
using Engine.Sgml.Configuration;
using System.Diagnostics;

namespace Engine.Sgml.Parser {
    internal sealed class CommentReader : IElementReader {
        private StringBuilder builder = new StringBuilder();

        public SElement Read(SgmlStreamReader reader, SElement parent, Context context) {
            SElement comment = parent.Nodes.Push();
            comment.Clear();
            comment.Parent = parent;
            comment.LineNumber = context.LineNumber;
            comment.LinePosition = context.LinePosition;
            comment.Name = DName.PCData.ToString();
            comment.DName = InclusionNode.Instance.Name;
            comment.NodeType = SgmlNodeType.Comment;

            if (reader.CurrentChar == Characters.EndTagMarkup) {
                comment.Value = string.Empty;
                reader.ReadChar();
                return comment;
                }
            builder.Clear();
            // Read comment
            char ch = reader.ReadChar();
            switch (ch) {
                case Characters.CommentMarkup:
                    ch = reader.ReadChar();
                    break;
                case Characters.EndTagMarkup:
                    comment.Value = string.Empty;
                    reader.ReadChar();
                    return comment;
                case Characters.EndOfFile:
                    comment.Value = string.Empty;
                    return comment;
                default:
                    builder.Append(ch);
                    ch = reader.ReadChar();
                    break;
                }
            context.SetLineInfo(reader);
            while (ch != Characters.EndOfFile) {
                // if '-->'
                if (ch == Characters.CommentMarkup) {
                    builder.Append(ch);
                    ch = reader.ReadChar();
                    if (ch == Characters.CommentMarkup) {
                        do {
                            builder.Append(ch);
                            ch = reader.ReadChar();
                            } while (ch == Characters.CommentMarkup);
                        if (ch == Characters.EndTagMarkup) {
                            builder.Remove(builder.Length - 2, 2);
                            reader.ReadChar();
                            break;
                            }
                        }
                    builder.Append(ch);
                    }
                else
                    builder.Append(ch);
                ch = reader.ReadChar();
                }
            if (ch == Characters.EndOfFile) {
                context.TraceSource.TraceEvent(TraceEventType.Error, 0, "Comment starting on {0} was not closed.", comment.Context());
                reader.Close();
                reader.Initialize(new StringReader(builder), context.LineNumber, context.LinePosition);

                builder = new StringBuilder();
                ch = reader.ReadChar();
                // if '>'
                while (ch != Characters.EndOfFile && ch != Characters.EndTagMarkup) {
                    builder.Append(ch);
                    ch = reader.ReadChar();
                    }
                if (ch == Characters.EndTagMarkup)
                    reader.ReadChar();
                }

            // Remove '--'
            for (int i = 0; i < builder.Length; i++) {
                if (builder[i] == Characters.CommentMarkup) {
                    int j = i + 1;
                    if (j == builder.Length)
                        builder.Remove(builder.Length - 1, 1);
                    else if (builder[j] == Characters.CommentMarkup) {
                        builder.Remove(i, 2);
                        --i;
                        }
                    }
                }
            // Set value
            comment.Value = builder.ToString();
            builder.Clear();
            return comment;
            }
        }
    }
